package gaml.java.serializer.collection;

import gaml.error.GamlException;
import gaml.java.ClassSerializer;
import gaml.java.ClassSerializerStore;
import gaml.java.NodeObjectBridge;
import gaml.yaml.EmptyNode;
import gaml.yaml.MappingNode;
import gaml.yaml.YamlNode;
import gaml.yaml.ahchor.YamlAnchorCodeStore;
import gaml.yaml.ahchor.YamlAnchorObjectStore;

import java.util.Iterator;
import java.util.Set;


/**
 * serialize-restore implementation of Set<E> interface
 * @author shnireck
 *
 * @param <T> class, that implements Set
 */
public abstract class SetSerializer <T extends Set <Object>> implements ClassSerializer <T> {
	static final String incorrectNodeError = "Node [%s] should be sequence node";
	static final String incorrectObjectError = "Object [%s] should implement set";
	ClassSerializerStore store = null;
	
	public SetSerializer (ClassSerializerStore store) { this.store = store; }

	@Override
	public YamlNode createNode (YamlNode parent) { return new MappingNode (parent); }

	@Override
	public boolean noAnchor () { return false; }

	@Override
	public YamlNode serialize (YamlNode node, T object, YamlAnchorObjectStore anchors) throws GamlException {
		if (! (node instanceof MappingNode)) throw new GamlException (String.format (incorrectNodeError, node));
		
		node.setTag (object.getClass ().getName ());
		for (Iterator <Object> i = object.iterator (); i.hasNext ();) {
			Object value = i.next ();
			node.addChild (NodeObjectBridge.create (value, node, (Class <Object>) value.getClass (), store).parseObject (anchors).getNode ().setTag (value.getClass ().getName ()), new EmptyNode (node));
		}

		return node;
	}
	
	@Override
	public T restore (YamlNode node, T object, YamlAnchorCodeStore anchors) throws GamlException {
		if (! (object instanceof Set)) throw new GamlException (String.format (incorrectObjectError, object));

		for (YamlNode value: node.getMappingChildren ().keySet ()) {
			try { object.add (NodeObjectBridge.create (value, (value.getTag ().isEmpty () ? Object.class : Class.forName (value.getTag ())), store).parseNode (anchors).getObject ()); }
			catch (ClassNotFoundException e) { throw new GamlException (e.toString ()); }
		}
		
		return object;
	}
}
